package org.rcgwt.client.ui.validator.impl;

import org.rcgwt.client.ui.validator.IClientValidatorContext;
import org.rcgwt.client.ui.validator.IFormatter;
import org.rcgwt.client.ui.validator.ISingleton;
import org.rcgwt.client.ui.validator.IValidatorElement;

/**
 * Formatter which formats a number in its scientific form (1254.23 ==>
 * 1.25423E3 or 0.002445 ==> 2.445E-3)
 * 
 * @author Elian ORIOU
 * 
 */

public class ScientificFormatter implements IFormatter, ISingleton {

	private static final ScientificFormatter INSTANCE = new ScientificFormatter();

	protected ScientificFormatter() {

	}

	@Override
	public String format(IClientValidatorContext context, String ttf) {

		/*
		 * If the digit doesn't contains a point
		 */
		if (!ttf.contains(".")) {
			int power = ttf.length() - 1;
			String leftPart = String.valueOf(ttf.charAt(0));
			String rightPart = ttf.substring(1);
			int nbLastZeros = 0;
			for (int i = rightPart.length() - 1; i >= 0; i--) {
				if (rightPart.charAt(i) == '0') {
					nbLastZeros++;
				} else {
					break;
				}
			}
			String rightPartWoZero = rightPart.substring(0, rightPart.length()
					- nbLastZeros);
			return leftPart + "." + rightPartWoZero + "E+" + power;
		}

		/*
		 * If the first not null integer is the first digit ==> Shifting point
		 * to the left ==> positive power
		 */
		else if (ttf.charAt(0) != '0') {
			int indexPoint = ttf.indexOf(".");
			int power = indexPoint - 1;
			return shiftPoint(ttf, -indexPoint + 1) + "E+" + power;
		}
		/*
		 * If the first not null integer is NOT the first digit ==> Shifting
		 * point to the right ==> negative power
		 */
		/* To avoid 000.111 for instance */
		else if (ttf.charAt(1) == '.') {
			int firstNND = firstNotNullDigit(ttf);
			int power = firstNND - 1;
			String result = shiftPoint(ttf, firstNND - 1);
			return result.substring(firstNotNullDigit(result)) + "E-" + power;
		} else {
			return ttf;
		}
	}

	/**
	 * Shift point to the left or to the right according to the offset signum
	 * 
	 * @param s
	 *            The string to modify
	 * @param offset
	 *            The offset
	 * @return The string modified
	 */

	private String shiftPoint(String s, int offset) {
		if (!s.contains("."))
			return s;
		else {
			int pointIndex = s.indexOf(".");
			String str = removeChar(s, pointIndex);
			String result = "";
			for (int i = 0; i < str.length(); i++) {
				if (i == (pointIndex + offset)) {
					result += ".";
				}
				result += str.charAt(i);
			}
			return result;
		}
	}

	/**
	 * Remove a char from a string at the specified position <i>pos</i>
	 * 
	 * @param s
	 *            The String to modify
	 * @param pos
	 *            The position of the character to remove
	 * @return The string modified
	 */

	private String removeChar(String s, int pos) {
		String leftPart = s.substring(0, pos);
		String rightPart = s.substring(pos + 1);
		return leftPart + rightPart;
	}

	/**
	 * Return the first not null digit position in the string
	 * 
	 * @param s
	 *            The string to analyze
	 * @return The position of the first not null digit
	 */

	private int firstNotNullDigit(String s) {
		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) != '0' && s.charAt(i) != '.') {
				return i;
			}
		}
		return -1;
	}

	public static IValidatorElement getInstance() {
		return INSTANCE;
	}
}
